--[[
	This file is part of FlexBar3.

	FlexBar3 is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	FlexBar3 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with FlexBar3.  If not, see <http://www.gnu.org/licenses/>.
]]
local Button = FlexBar3:GetModule("Button");
local AttributeButton = Button:NewButtonClass("AttributeButton", 1);

function AttributeButton:LoadSettings()
	if(self.DB.Type == "AttributeAction") then
		self:ApplyActions();
	end
end

function AttributeButton:Enable()
	if(self.DB.Type == "AttributeAction") then
		self:AttributeAction_Register();
		self:RefreshActionTexture();
	end
	self:RegisterCallback("TypeChanged", self.AttributeButton_TypeChanged);
	self:RegisterCallback("ModifiersChanged", self.CheckForNewAction);
end

function AttributeButton:Disable()
	self:UnregisterCallback("TypeChanged", self.AttributeButton_TypeChanged);
	self:UnregisterCallback("ModifiersChanged", self.CheckForNewAction);
end


function AttributeButton:AttributeAction_Register()
	self:RegisterScript("PreClick", self.CheckCursorForAction);
	self:RegisterScript("PostClick", self.CheckDisabledAction);
	self:RegisterScript("OnReceiveDrag", self.CheckCursorForAction);
	self:RegisterScript("OnDragStart", self.DragActionOff);
	self:RegisterCallback("ActionChanged", self.RefreshActionTexture);
end

function AttributeButton:AttributeAction_Unregister()
	self:UnregisterScript("PreClick", self.CheckCursorForAction);
	self:UnregisterScript("PostClick", self.CheckDisabledAction);
	self:UnregisterScript("OnReceiveDrag", self.CheckCursorForAction);
	self:UnregisterScript("OnDragStart", self.DragActionOff);
	self:UnregisterCallback("ActionChanged", self.RefreshActionTexture);
end

function AttributeButton:ApplyActions()
	for CurrentStateName, CurrentStateDB in pairs(self.StateDB) do
		if(CurrentStateName ~= "DefaultState") then
			local Type = CurrentStateDB.Type;
			if(Type == "spell") then
				if(CurrentStateDB.SpellName) then
					self:PlaceSpell(CurrentStateDB.SpellName, CurrentStateDB.SpellRank, CurrentStateName);
				end
			elseif(Type == "item") then
				if(CurrentStateDB.Itemlink) then
					self:PlaceItem(CurrentStateDB.Itemlink, CurrentStateName);
				end
			elseif(Type == "macro") then
				if(CurrentStateDB.MacroName) then
					self:PlaceMacro(CurrentStateDB.MacroName, CurrentStateName);
				end
			end
		end
	end
end

function AttributeButton:PlaceAction(Type, Action, ActionBook)
	if(Type == "spell") then
		local SpellName, SpellRank = GetSpellName(Action, ActionBook);
		local SpellRank = string.match(Action, (RANK .." (%d+)$"));
		SpellRank = tonumber(SpellRank);
		self:PlaceSpell(SpellName, SpellRank);
		ClearCursor();
		return Type, SpellName, SpellRank;
	elseif(Type == "item") then
		local Itemlink = string.gsub(ActionBook, "(.*):(.-)$", "%1:0");
		local Itemlink = ActionBook;
		self:PlaceItem(Itemlink);
		ClearCursor();
		return Type, Itemlink;
	elseif(Type == "macro") then
		local MacroName, _, MacroBody = GetMacroInfo(Action);
		self:PlaceMacro(MacroName, MacroBody);
		ClearCursor();
		return Type, MacroName;
	end
	return Type, Action, ActionBook;
end

function AttributeButton:PickupAction(ActionType, ...)
	-- Make sure the cursor is clear before picking anything up
	ClearCursor();
	if(ActionType == "spell") then
		PickupSpell(...);
	elseif(ActionType == "item") then
		PickupItem((select(1, ...)):sub(10));
	elseif(ActionType == "macro") then
		PickupMacro(...);
	end
end

function AttributeButton:DragActionOff()
	local Type = self:GetModifiedAttribute("type")
	if(Type == "spell") then
		self:DragSpellOff();
	elseif(Type == "item") then
		self:DragItemOff();
	elseif(Type == "macro") then
		self:DragMacroOff();
	end
end

-- Reenable the button after it was disabled. only works OUT of combat
function AttributeButton:EnableAction()
	if(InCombatLockdown() == nil) then
		if(self.DisabledActionTypeLeft ~= nil) then
			self:SetModifiedAttribute("type", self.DisabledActionTypeLeft, false);
			self.DisabledActionTypeLeft = nil;
		end
		if(self.DisabledActionTypeRight ~= nil) then
			self:SetModifiedAttribute("type-RightButton", self.DisabledActionTypeRight, false);
			self.DisabledActionTypeRight = nil;
		end
		if(self.DisabledActionTypeMiddle ~= nil) then
			self:SetModifiedAttribute("type-MiddleButton", self.DisabledActionTypeMiddle, false);
			self.DisabledActionTypeMiddle = nil;
		end
	end
end

-- Disable the button, this should not be used for log disablings. only works OUT of combat
function AttributeButton:DisableAction()
	if(InCombatLockdown() == nil) then
		self.DisabledActionTypeLeft = self:GetModifiedAttribute("type");
		self.DisabledActionTypeRight = self:GetModifiedAttribute("type-RightButton");
		self.DisabledActionTypeMiddle = self:GetModifiedAttribute("type-MiddleButton");
		self:SetModifiedAttribute("type", nil);
		self:SetModifiedAttribute("type-RightButton", nil);
		self:SetModifiedAttribute("type-MiddleButton", nil);
	end
end

function AttributeButton:RefreshActionTexture()
	local Type = self:GetModifiedAttribute("type");
	if(Type == "spell") then
		self:RefreshSpellTexture();
	elseif(Type == "item") then
		self:RefreshItemTexture();
	elseif(Type == "macro") then
		self:RefreshMacroTexture();
	elseif(not Type or Type == "") then
		self:SetTexture(nil);
	end
end

function AttributeButton:CheckCursorForAction(Trigger)
	local Type, Action, ActionBook = GetCursorInfo();
	if(Type and InCombatLockdown() == nil) then
		local OldActionType = self:GetModifiedAttribute("type");
		local OldActionAttribute;
		if(OldActionType and OldActionType ~= "") then
			OldActionAttribute = self:GetModifiedAttribute(OldActionType);
		end
		local Type, Action, ActionBook = self:PlaceAction(Type, Action, ActionBook);
		local CurrentStateDB = self.StateDB[self:GetModifiedState()];
		if(Type == "spell") then
			CurrentStateDB.Type = "spell";
			CurrentStateDB.SpellName = Action;
			CurrentStateDB.SpellRank = ActionBook;
		elseif(Type == "item") then
			CurrentStateDB.Type = "item";
			CurrentStateDB.Itemlink = Action;
		elseif(Type == "macro") then
			CurrentStateDB.Type = "macro";
			CurrentStateDB.MacroName = Action;
		end
		if(OldActionType and OldActionAttribute) then
			self:PickupAction(OldActionType, OldActionAttribute);
		end
		-- Disable the button to ensure the click doesn't go through
		if(Trigger == "PreClick") then
			self:DisableAction();
			self.DisabledForAction = true;
		end
	end
end

function AttributeButton:CheckDisabledAction()
	if(self.DisabledForAction == true) then
		self:EnableAction();
		self.DisabledForAction = false;
	end
end

function AttributeButton:CheckForNewAction(Callback, OldPrefix, OldSuffix, NewPrefix, NewSuffix)
	local OldModifier = ("%s%s%s"):format(OldPrefix, "%s", OldSuffix);
	local NewModifier = ("%s%s%s"):format(NewPrefix, "%s", NewSuffix);
	local OldType = self:GetModifiedAttribute("type", OldModifier);
	local NewType = self:GetModifiedAttribute("type", NewModifier);
	local OldAttribute, NewAttribute;
	if(OldType and NewType and OldType ~= "" and NewType ~= "") then
		OldAttribute = self:GetModifiedAttribute(OldType, OldModifier);
		NewAttribute = self:GetModifiedAttribute(NewType, NewModifier);
	end
	if(OldType ~= NewType or OldAttribute ~= NewAttribute) then
		self:TriggerCallback("ActionChanged");
	end
end

function AttributeButton:AttributeButton_TypeChanged(Callback, OldType, NewType)
	if(OldType == "Attribute" and NewType ~= "Attribute") then
		self:AttributeSpellClass_Unregister();
	elseif(OldType ~= "Attribute" and NewType == "Attribute") then
		self:AttributeSpellClass_Register();
	end
end
